package czh.cocoa.ui;

import czh.cocoa.animation.CAAnimation;
import czh.cocoa.animation.CAAnimationDelegate;
import czh.cocoa.animation.CAAnimationGroup;
import czh.cocoa.animation.CABasicAnimation;
import czh.cocoa.animation.CALayer;
import czh.cocoa.animation.CALayerDelegate;
import czh.cocoa.animation.CATransform3D;
import czh.cocoa.animation.CATransformAction;
import czh.cocoa.foundation.NSArray;
import czh.cocoa.foundation.NSMutableArray;
import czh.cocoa.foundation.NSNull;
import czh.cocoa.foundation.NSObject;
import czh.cocoa.foundation.NSSet;
import czh.cocoa.foundation.NSString;
import czh.cocoa.foundation.NSValue;
import czh.cocoa.graphics.CGAffineTransform;
import czh.cocoa.graphics.CGColor;
import czh.cocoa.graphics.CGContext;
import czh.cocoa.graphics.CGPoint;
import czh.cocoa.graphics.CGRect;
import czh.cocoa.graphics.CGSize;

import static czh.cocoa.graphics.CGContext.*;
import static czh.cocoa.ui.UIKit.*;
import static czh.cocoa.animation.CALayer.*;

public class UIView extends UIResponder implements CALayerDelegate {

	public final static int UIViewAutoresizingNone                 = 0;
	public final static int UIViewAutoresizingFlexibleLeftMargin   = 1 << 0;
	public final static int UIViewAutoresizingFlexibleWidth        = 1 << 1;
	public final static int UIViewAutoresizingFlexibleRightMargin  = 1 << 2;
	public final static int UIViewAutoresizingFlexibleTopMargin    = 1 << 3;
	public final static int UIViewAutoresizingFlexibleHeight       = 1 << 4;
	public final static int UIViewAutoresizingFlexibleBottomMargin = 1 << 5;
	
	public final static int UIViewAutoresizingFlexibleSize = 
						UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
	
	public final static int UIViewContentModeScaleToFill = 0;
	public final static int UIViewContentModeScaleAspectFit = 1;
	public final static int UIViewContentModeRedraw = 2;
	public final static int UIViewContentModeCenter = 3;
	
	private static NSMutableArray sAnimations;
	
	private CALayer mLayer;
	
	private UIView mSuperview;
	
	private NSMutableArray mSubviews;
	
	private UIColor mBackgroundColor;
	
	private int mTag;
	
	private int mAutoresizingMask;
	
	private boolean mAutoresizesSubviews;
	
	private int mContentMode;
	
	private NSMutableArray mGestureRecognizers;
	
	private boolean mUserInteractionEnabled;
	
	private boolean mMultipleTouchEnabled;
	
	private boolean mExclusiveTouch;
	
	private CGRect mContentStretch;
	
	private UIViewController mViewDelegate;
	
	private UIWindow mWindow;

	public UIView() {
		
	}
	
	public UIView(CGRect frame) {
		setFrame(frame);
	}
	
	protected void init() {
		super.init();
		mLayer = new CALayer();
		mLayer.setDelegate(this);
		mSubviews = new NSMutableArray(3);
		mAutoresizingMask = UIViewAutoresizingNone;
		mAutoresizesSubviews = true;
		mContentMode = UIViewContentModeScaleToFill;
		mGestureRecognizers = new NSMutableArray(3);
		mUserInteractionEnabled = true;
		mContentStretch = CGRectMake(0, 0, 1, 1);
	}
	
	public CALayer layer() {
		return mLayer;
	}
	
	public void drawRect(CGRect rect) {
		
	}

	@Override
	public boolean displayLayer(CALayer layer) {
		return false;
	}

	@Override
	public void drawLayerInContext(CALayer layer, CGContext ctx) {
		
		CGRect bounds = bounds();
		
		if(mBackgroundColor != null) {
			CGContextSaveGSState(ctx);
			CGContextSetFillColorWithColor(ctx, mBackgroundColor.CGColor());
			CGContextFillRect(ctx, bounds);
			CGContextRestoreGSState(ctx);
		}
		
		UIGraphicsPushContext(ctx);
		drawRect(bounds);
		UIGraphicsPopContext();
	} 
	
	public CGRect frame() {
		return mLayer.frame();
	}
	
	public CGRect bounds() {
		return mLayer.bounds();
	}
	
	public CGPoint center() {
		CGRect frame = frame();
		return new CGPoint(frame.origin.x + frame.size.width / 2, 
				           frame.origin.y + frame.size.height / 2);
	}
	
	public void setFrame(CGRect frame) {
//		CGRect frame0 = frame();
//		mLayer.setFrame(frame);
//		
//		if(frame.size.width != frame0.size.width || 
//				frame.size.height != frame0.size.height) {
//			autoresizesSubviews(frame, frame0);
//			
//			if (mContentMode == UIViewContentModeRedraw) {
//				setNeedsDisplay();
//			}
//		}
		mLayer.setFrame(frame); 
	}
	
	public void setBounds(CGRect bounds) {
		mLayer.setBounds(bounds); 
	}
	
	public void setCenter(CGPoint center) {
		mLayer.setCenter(center);
	}
	
	public UIView superview() {
		return mSuperview;
	}
	
	public NSArray subviews() {
		return new NSArray(mSubviews);
	}
	
	public void addSubview(UIView view) {
		insertSubviewAtIndex(view, mSubviews.count());
	}
	
	public void insertSubviewAboveSubview(UIView view, UIView siblingSubview) {
		int index = mSubviews.indexOfObject(siblingSubview);
		if (index != NSNotFound) {
			insertSubviewAtIndex(view, index + 1);
		} else {
			addSubview(view);
		}
	}
	
	public void insertSubviewBelowSubview(UIView view, UIView siblingSubview) {
		int index = mSubviews.indexOfObject(siblingSubview);
		if (index != NSNotFound) {
			insertSubviewAtIndex(view, index);
		} else {
			addSubview(view);
		}
	}
	
	public void insertSubviewAtIndex(UIView view, int index) {
		if (view.superview() != this) {
			
			view.removeFromSuperview();
			
			UIWindow window = window();
			
			if (window != null) { 
				UIViewController delegate = view.viewDelegate();
				if (delegate != null) {
					delegate.viewWillAppear();
				}
			}
			
			view.mSuperview = this;	
			mSubviews.insertObjectAtIndex(view, index);
			mLayer.insertSublayerAtIndex(view.layer(), index);
			
			if (window != null) { 
				UIViewController delegate = view.viewDelegate();
				if (delegate != null) {
					delegate.viewDidAppear();
				}
			}
			
		} else {
			
			mSubviews.removeObject(view);
			if (index < mSubviews.count()) { 
				mSubviews.insertObjectAtIndex(view, index);
			} else {
				mSubviews.addObject(view);
			}
			
			mLayer.insertSublayerAtIndex(view.layer(), index);
			
		}
		
		
		
	}
	
	public void bringSubviewToFront(UIView view) {
		int index = mSubviews.indexOfObject(view);
		if (index != NSNotFound && index != mSubviews.count() - 1) {
			view.removeFromSuperview();
			addSubview(view);
		}
	}
	
	public void sendSubviewToBack(UIView view) {
		int index = mSubviews.indexOfObject(view);
		if (index != NSNotFound && index != 0) {
			view.removeFromSuperview();
			insertSubviewAtIndex(view, 0);
		}
	}
	
	public void removeFromSuperview() {
		if(mSuperview != null) {
			UIWindow window = window();
			
			if (window != null) { 
				if (mViewDelegate != null) {
					mViewDelegate.viewWillDisappear();
				}
			}
			
			mSuperview.mSubviews.removeObject(this);
			mSuperview = null;
			mLayer.removeFromSuperlayer();
			
			if (window != null) { 
				if (mViewDelegate != null) {
					mViewDelegate.viewDidDisappear();
				}
			}
		}
	}
	
	//additional
	public void clearAllSubviews() {
		NSArray subviews = subviews();
		for (NSObject o : subviews) {
			UIView subview = (UIView) o;
			subview.removeFromSuperview();
		}
	}
	
	public UIView viewWithTag(int tag) {
		for (NSObject o : mSubviews) {
			UIView subview = (UIView) o;
			if (subview.tag() == tag) {
				return subview;
			}
		}
		return null;
	}
	
	public UIColor backgroundColor() {
		return new UIColor(mBackgroundColor); 
	}
	
	public void setBackgroundColor(UIColor color) {
		mBackgroundColor = new UIColor(color);
		setNeedsDisplay();
	}
	
	public UIWindow window() {
		UIView superview = mSuperview;
		UIView superview0 = null;
		while(superview != null) {
			superview0 = superview;
			superview = superview.superview();
		}
		if (superview0 != null && superview0 instanceof UIWindow) {
			return (UIWindow) superview0;
		}
		return null;
	}
	
	public void setAlpha(float alpha) {
		mLayer.setOpacity(alpha);
	}
	
	public float alpha() {
		return mLayer.opacity();
	}
	
	public void setHidden(boolean hidden) {
		mLayer.setHidden(hidden);
	}
	
	public boolean isHidden() {
		return mLayer.isHidden(); 
	}
	
	public void setNeedsDisplay() {
		mLayer.setNeedsDisplay();
	}
	
	public void setTransform(CGAffineTransform t) {
		mLayer.setTransform(t.transform3d());
	}
	
	public CGAffineTransform transform() {
		return new CGAffineTransform(mLayer.transform()); 
	}
	
	public void setTransform(CATransformAction t) { 
		mLayer.setTransform(t);
	}
	
	public void setNeedsLayout() {
		mLayer.setNeedsLayout();
	}
	
	@Override
	public void layoutSublayersOfLayer(CALayer layer) {
		layoutSubviews();
	}
	
	public void layoutSubviews() {
		
	}

	@Override
	public NSObject actionForLayerForKey(CALayer layer, NSString key, NSObject value) {
		if (sAnimations != null) {
			
			if(key.isEqual(ANIM_OPACITY) || key.isEqual(ANIM_FRAME) || key.isEqual(ANIM_BOUNDS)) {
				CABasicAnimation anim = new CABasicAnimation(key);
				anim.setFromValue(value);
				UIViewAnimation va = findViewAnimation(this);
				va.animations.addObject(anim);
			} else if(key.isEqual(ANIM_TRANSFORM)) {
				CABasicAnimation anim = new CABasicAnimation(key);
				anim.setToValue(value);
				UIViewAnimation va = findViewAnimation(this);
				va.animations.addObject(anim);
			}
			
		}
		
//		if(value.isEqual(ANIM_FRAME)) {
//			autoresizesSubviews(frame(), (CGRect) value);
//		}
		
		return NSNull.nil();
	}
	
	public void setTag(int tag) {
		mTag = tag;
	}
	
	public int tag() {
		return mTag;
	}
	
	public void setAutoresizingMask(int autoresize) {
		mAutoresizingMask = autoresize;
	}
	
	public int autoresizingMask() {
		return mAutoresizingMask;
	}
	
	public void setAutoresizesSubviews(boolean autoresize) {
		mAutoresizesSubviews = autoresize;
	}
	
	public boolean isAutoresizesSubviews() {
		return mAutoresizesSubviews;
	}
	
	private void autoresizesSubviews(CGRect frame, CGRect frame0) {
		if (mAutoresizesSubviews) {
			
			for (NSObject o : mSubviews) {
				UIView subview = (UIView) o;
				
				int autoresize = subview.autoresizingMask();
				if (autoresize != UIViewAutoresizingNone) {
					
					CGRect subf = subview.frame();
					
					float left_margin = subf.origin.x;
					float right_margin = frame0.size.width - (subf.origin.x + subf.size.width);
					float top_margin = subf.origin.y;
					float bottom_margin = frame0.size.height - (subf.origin.y + subf.size.height);
					
					if((autoresize & UIViewAutoresizingFlexibleLeftMargin) != 
						  UIViewAutoresizingFlexibleLeftMargin) {
						
						if((autoresize & UIViewAutoresizingFlexibleRightMargin) != 
							UIViewAutoresizingFlexibleRightMargin) {
							
							if((autoresize & UIViewAutoresizingFlexibleWidth) == 
								UIViewAutoresizingFlexibleWidth) {
								
								subf.size.width += (frame.size.width - frame0.size.width);
								
							}
							
							
						} else {
							
							if((autoresize & UIViewAutoresizingFlexibleWidth) == 
								UIViewAutoresizingFlexibleWidth) {
								
								subf.size.width += (frame.size.width - frame0.size.width) / 
								         (frame0.size.width - left_margin) * subf.size.width;
								
							}
							
							
						}
						
						
					} else {
						
						
						if((autoresize & UIViewAutoresizingFlexibleRightMargin) != 
							UIViewAutoresizingFlexibleRightMargin) {
							
							if((autoresize & UIViewAutoresizingFlexibleWidth) == 
								UIViewAutoresizingFlexibleWidth) {
								
								subf.size.width += (frame.size.width - frame0.size.width) / 
						         		(frame0.size.width - right_margin) * subf.size.width;
								
							} 
								
							subf.origin.x = frame.size.width - subf.size.width - right_margin;
								
							
						} else {
							
							float margin0 = frame0.size.width - subf.size.width;
							
							if((autoresize & UIViewAutoresizingFlexibleWidth) == 
								UIViewAutoresizingFlexibleWidth) {
								
								subf.size.width *= (frame.size.width / frame0.size.width);
								
							} 
							
							float margin = frame.size.width - subf.size.width;
							
							subf.origin.x = left_margin * (margin / margin0);
							
						}
						
						
					}
					
					if((autoresize & UIViewAutoresizingFlexibleTopMargin) != 
						UIViewAutoresizingFlexibleTopMargin) {
						
						if((autoresize & UIViewAutoresizingFlexibleBottomMargin) != 
							UIViewAutoresizingFlexibleBottomMargin) {
							
							if((autoresize & UIViewAutoresizingFlexibleHeight) == 
								UIViewAutoresizingFlexibleHeight) {
								
								subf.size.height += (frame.size.height - frame0.size.height);
								
							}
							
							
						} else {
							
							if((autoresize & UIViewAutoresizingFlexibleHeight) == 
								UIViewAutoresizingFlexibleHeight) {
								
								subf.size.height += (frame.size.height - frame0.size.height) / 
								         (frame0.size.height - top_margin) * subf.size.height;
								
							}
							
							
						}
						
						
					} else {
						
						if((autoresize & UIViewAutoresizingFlexibleBottomMargin) != 
							UIViewAutoresizingFlexibleBottomMargin) {
							
							if((autoresize & UIViewAutoresizingFlexibleHeight) == 
								UIViewAutoresizingFlexibleHeight) {
								
								subf.size.height += (frame.size.height - frame0.size.height) / 
						         		(frame0.size.height - bottom_margin) * subf.size.height;
								
							} 
								
							subf.origin.y = frame.size.height - subf.size.height - bottom_margin;
								
							
						} else {
							
							float margin0 = frame0.size.height - subf.size.height;
							
							if((autoresize & UIViewAutoresizingFlexibleHeight) == 
								UIViewAutoresizingFlexibleHeight) {
								
								subf.size.height *= (frame.size.height / frame0.size.height);
								
							} 
							
							float margin = frame.size.height - subf.size.height;
							
							subf.origin.y = top_margin * (margin / margin0);
							
						}
						
						
					}
					
					subview.setFrame(subf);
					
				}
				
			}
			
		}
	}
	
	public void setContentMode(int mode) {
		mContentMode = mode;
		switch (mode) {
			case UIViewContentModeScaleToFill:
			case UIViewContentModeRedraw:
				mLayer.setContentsGravity(kCAGravityResize);
				break;
			case UIViewContentModeScaleAspectFit:
				mLayer.setContentsGravity(kCAGravityResizeAspect);
				break;
			case UIViewContentModeCenter:
				mLayer.setContentsGravity(kCAGravityCenter);
				break;
			default:
				break;
		}
	}
	
	public int contentMode() {
		return mContentMode;
	}
	
	public UIView hitTestWithEvent(CGPoint point, UIEvent event) {
		NSArray subviews = subviews();
		for (int i = subviews.count() - 1; i >= 0; i--) {
			UIView subview = (UIView) subviews.objectAtIndex(i);
			if (subview.isUserInteractionEnabled() && !subview.isHidden() &&
					subview.alpha() >= 0.01 && subview.pointInsideWithEvent(point, event)) {
				CGRect frame = subview.frame();
				CGRect bounds = subview.bounds();
				CGPoint point2 = new CGPoint(point.x - frame.origin.x + bounds.origin.x, 
						                     point.y - frame.origin.y + bounds.origin.y);
				return subview.hitTestWithEvent(point2, event); 
			}
		}
		return this;
	}
	
	public boolean pointInsideWithEvent(CGPoint point, UIEvent event) {
		return frame().containsPoint(point); 
	}
	
	public UIResponder nextResponder() {
		return mViewDelegate != null ? mViewDelegate : mSuperview;
	}
	
	public CGPoint convertPointFromView(CGPoint point, UIView view) {
		CGPoint ret = new CGPoint(point);
		
		CGPoint p = new CGPoint();
		UIView subview = (view != null) ? view : window();
		
		if(subview == null) {
			return ret;
		}
		
		UIView superview = subview.superview();
		while (superview != null) {
			CGRect frame = subview.frame();
			p.offset(frame.origin.x, frame.origin.y);
			subview = superview;
			superview = subview.superview();
		}
		
		CGPoint p2 = new CGPoint();
		UIView subview2 = this;
		UIView superview2 = subview2.superview();
		while (superview2 != null) {
			CGRect frame = subview2.frame();
			p2.offset(frame.origin.x, frame.origin.y);
			subview2 = superview2;
			superview2 = subview2.superview();
		}
		
		if(subview == subview2) {  //the same window
			ret.offset(p.x, p.y); 
			ret.offset(-p2.x, -p2.y); 
		}
		
		return ret;
	}
	
	public CGPoint convertPointToView(CGPoint point, UIView view) {
		UIView view2 = (view != null) ? view : window();
		return view2.convertPointFromView(point, this);
		
	}
	
	public NSArray gestureRecognizers() {
		return new NSArray(mGestureRecognizers);
	}
	
	public void addGestureRecognizer(UIGestureRecognizer recoginzer) {
		mGestureRecognizers.addObject(recoginzer);
		recoginzer.setView(this);
	}
	
	public void removeGestureRecognizer(UIGestureRecognizer recoginzer) {
		if (mGestureRecognizers.containsObject(recoginzer)) {
			mGestureRecognizers.removeObject(recoginzer);
			recoginzer.setView(null);
		}
	}
	
	public void setUserInteractionEnabled(boolean enabled) {
		mUserInteractionEnabled = enabled;
	}
	
	public boolean isUserInteractionEnabled() {
		return mUserInteractionEnabled;
	}
	
	public void setMultipleTouchEnabled(boolean enabled) {
		mMultipleTouchEnabled = enabled;
	}
	
	public boolean isMultipleTouchEnabled() {
		return mMultipleTouchEnabled;
	}
	
	public void setExclusiveTouch(boolean exclusive) {
		mExclusiveTouch = exclusive;
	}
	
	public boolean isExclusiveTouch() {
		return mExclusiveTouch;
	}
	
	public void setContentStretch(CGRect stretch) {
		mContentStretch = stretch;
	}
	
	public CGRect contentStretch() {
		return new CGRect(mContentStretch);
	}
	
	public void setClipsToBounds(boolean clips) {
		mLayer.setMasksToBounds(clips);
	}
 	
	public boolean clipsToBounds() {
		return mLayer.masksToBounds();
	}
	
	public void layerSizeDidChanged(CALayer layer, CGRect oldFrame) {
		autoresizesSubviews(layer.frame(), oldFrame);
		if (mContentMode == UIViewContentModeRedraw) {
			setNeedsDisplay();
		}
	}
	
	public CGSize sizeThatFits(CGSize size) {
		return new CGSize(size);  
	}
	
	public void sizeToFit() {
		CGRect bounds = bounds();
		bounds.size = sizeThatFits(bounds.size);
		setBounds(bounds);
	}
	
	public NSString description() {
		return NSTR(getClass().getSimpleName() + frame()); 
	}
	
//	– didAddSubview:
//	– willRemoveSubview:
//	– willMoveToSuperview:
//	– didMoveToSuperview
//	– willMoveToWindow:
//	– didMoveToWindow
	
	void setViewDelegate(UIViewController ctrl) {
		mViewDelegate = ctrl;
	}
	
	UIViewController viewDelegate() {
		return mViewDelegate;
	}
	
	public static void animateWithDurationAnimations(double duration, UIAnimationBlock block) {
		animateWithDurationAnimationsCompletion(duration, block, null);
	}
	
	public static void animateWithDurationAnimationsCompletion(double duration, 
			UIAnimationBlock block, UIAnimationBlock.Completion completion) {
		sAnimations = new NSMutableArray();
		
		if(block != null) {
			block.run();
		}
		
		int count = sAnimations.count();
		
		for (int i = 0; i < count; i++) {
			UIViewAnimation anim = (UIViewAnimation) sAnimations.objectAtIndex(i);
			CAAnimation group = new CAAnimationGroup(anim.animations);
			group.setDuration(duration);
			anim.view.layer().addAnimationForKey(group, null);
			
			if (i == count - 1 && completion != null) {
				
				final UIAnimationBlock.Completion c = completion;
				
				group.setDelegate(new CAAnimationDelegate() {
					@Override
					public void animationDidStop(CAAnimation anim, boolean finished) {
						c.run(finished);
					}
					@Override
					public void animationDidStart(CAAnimation anim) {}
					@Override
					public void animationOnProcessing(CAAnimation anim) {}
				});
			}
			
		}
		sAnimations = null;
	}
	
	private static UIViewAnimation findViewAnimation(UIView view) {
		for (int i = 0; i < sAnimations.count(); i++) {
			UIViewAnimation anim = (UIViewAnimation) sAnimations.objectAtIndex(i);
			if (anim.view == view) {
				return anim;
			}
		}
		UIViewAnimation anim = new UIViewAnimation(view);
		sAnimations.addObject(anim);
		return anim;
	}
	
	private static class UIViewAnimation extends NSObject {
		
		public UIView view;
		
		public NSMutableArray animations;
		
		public UIViewAnimation(UIView view) {
			this.view = view;
			animations = new NSMutableArray();
		}
		
	}

}
